package com.leo.interview;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 （Google面试题）有四个线程1、2、3、4。线程1的功能就是输出1，线程2的功能就是输出2，以此类推.........现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式：
 A：1 2 3 4 1 2....
 B：2 3 4 1 2 3....
 C：3 4 1 2 3 4....
 D：4 1 2 3 4 1....
 请设计程序。

 版本一：设计的四个线程，线程间完全独立。和轮询的思想十分相似，线程各自尝试去获取文件锁，然后再看是否能写入当前文件。
        当前十分低效，但如果 写操作 消耗的时间越多，效率就越高。
 一次输出例子如下：
         1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1
         2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1
         3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3
         4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3
 * @author xuexiaolei
 * @version 2017年11月14日
 */
public class Interview6 {
    private static final AtomicInteger count = new AtomicInteger(0);
    ///模拟四个文件
    private static final StringBuffer fileA = new StringBuffer();
    private static final StringBuffer fileB = new StringBuffer();
    private static final StringBuffer fileC = new StringBuffer();
    private static final StringBuffer fileD = new StringBuffer();
    //四个文件的锁
    private static final ReentrantLock lockA = new ReentrantLock();
    private static final ReentrantLock lockB = new ReentrantLock();
    private static final ReentrantLock lockC = new ReentrantLock();
    private static final ReentrantLock lockD = new ReentrantLock();
    //四个文件的书写位置
    private static final AtomicInteger numberA = new AtomicInteger(1);
    private static final AtomicInteger numberB = new AtomicInteger(2);
    private static final AtomicInteger numberC = new AtomicInteger(3);
    private static final AtomicInteger numberD = new AtomicInteger(4);

    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec = Executors.newFixedThreadPool(4);
        exec.execute(new writeTask(1));
        exec.execute(new writeTask(2));
        exec.execute(new writeTask(3));
        exec.execute(new writeTask(4));
        exec.shutdown();
        Thread.sleep(5000);//等待线程池结束后输出文件内容
        System.out.println(fileA);
        System.out.println(fileB);
        System.out.println(fileC);
        System.out.println(fileD);
    }

    static class writeTask implements Runnable{
        private final int wirteContent;//输出的内容，线程1的功能就是输出1，线程2的功能就是输出2
        writeTask(int wirteContent) {
            this.wirteContent = wirteContent;
        }
        @Override public void run() {
            while (count.get() < 1000) {//1000为多个线程总共大概尝试的次数
                //尝试写入A文件
                try {
                    boolean a = lockA.tryLock(1, TimeUnit.MILLISECONDS);
                    if (a) {
                        if (numberA.get() % 4 == wirteContent%4) {
                            fileA.append(wirteContent + " ");
                            numberA.incrementAndGet();
                        }
                        lockA.unlock();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //尝试写入文件
                try {
                    boolean a = lockB.tryLock(1, TimeUnit.MILLISECONDS);
                    if (a) {
                        if (numberB.get() % 4 == wirteContent%4) {
                            fileB.append(wirteContent + " ");
                            numberB.incrementAndGet();
                        }
                        lockB.unlock();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //尝试写入C文件
                try {
                    boolean a = lockC.tryLock(1, TimeUnit.MILLISECONDS);
                    if (a) {
                        if (numberC.get() % 4 == wirteContent%4) {
                            fileC.append(wirteContent + " ");
                            numberC.incrementAndGet();
                        }
                        lockC.unlock();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //尝试写入D文件
                try {
                    boolean a = lockD.tryLock(1, TimeUnit.MILLISECONDS);
                    if (a) {
                        if (numberD.get() % 4 == wirteContent%4) {
                            fileD.append(wirteContent + " ");
                            numberD.incrementAndGet();
                        }
                        lockD.unlock();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count.incrementAndGet();
            }
        }
    }
}
